package com.skivingcloud.admin.conf;

import com.skivingcloud.common.exceptions.BusinessException;
import com.skivingcloud.common.utils.UuidUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 缓存实现重复提交
 * @author hushouquan
 * @since 2024/6/24
 */
@Aspect
@Component
public class RedisRequestLockAspect{
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    
    @Around("@annotation(com.skivingcloud.admin.conf.RequestLock)")
    public Object interceptor(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        RequestLock requestLock = method.getAnnotation(RequestLock.class);
        if (StringUtils.isEmpty(requestLock.prefix())) {
            throw new BusinessException("重复提交前缀不能为空");
        }
        //获取自定义key
        final String lockKey = RequestKeyGenerator.getLockKey(joinPoint);
        // 使用RedisCallback接口执行set命令，设置锁键；设置额外选项：过期时间和SET_IF_ABSENT选项
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        final Boolean success = redisTemplate.opsForValue().setIfAbsent(lockKey, UuidUtil.get16NumUUID(), requestLock.expire(), requestLock.timeUnit());
        if (Boolean.FALSE.equals(success)) {
            throw new BusinessException("您的操作太快了,请稍后重试");
        }
        try {
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            throw new BusinessException("系统异常");
        }
    }
}
